{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "kcF9ZWvjSybR"
   },
   "source": [
    "# 10 Minutes to RAPIDS cuDF's pandas accelerator mode (cudf.pandas)\n",
    "\n",
    "cuDF is a Python GPU DataFrame library (built on the Apache Arrow columnar memory format) for loading, joining, aggregating, filtering, and otherwise manipulating tabular data using a DataFrame style API in the style of pandas.\n",
    "\n",
    "cuDF now provides a pandas accelerator mode (`cudf.pandas`), allowing you to bring accelerated computing to your pandas workflows without requiring any code change.\n",
    "\n",
    "This notebook is a short introduction to `cudf.pandas`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "SH_h6ci1Sx0u"
   },
   "source": [
    "# ⚠️ Verify your setup\n",
    "\n",
    "First, we'll verify that you are running with an NVIDIA GPU."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Y2vPCtXcCvUR",
    "outputId": "bbc9fe46-ad25-4781-ff8d-5a7a5bbefb41",
    "tags": []
   },
   "outputs": [],
   "source": [
    "!nvidia-smi  # this should display information about available GPUs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4zGUeWvcTbDs"
   },
   "source": [
    "# Download the data\n",
    "\n",
    "The data we'll be working with is the [Parking Violations Issued - Fiscal Year 2022](https://data.cityofnewyork.us/City-Government/Parking-Violations-Issued-Fiscal-Year-2022/7mxj-7a6y) dataset from NYC Open Data.\n",
    "\n",
    "We're downloading a copy of this dataset from an s3 bucket hosted by NVIDIA to provide faster download speeds. We'll start by downloading the data. This should take about 30 seconds.\n",
    "\n",
    "## Data License and Terms\n",
    "As this dataset originates from the NYC Open Data Portal, it's governed by their license and terms of use.\n",
    "\n",
    "### Are there restrictions on how I can use Open Data?\n",
    "\n",
    "> Open Data belongs to all New Yorkers. There are no restrictions on the use of Open Data. Refer to Terms of Use for more information.\n",
    "\n",
    "### [Terms of Use](https://opendata.cityofnewyork.us/overview/#termsofuse)\n",
    "\n",
    "> By accessing datasets and feeds available through NYC Open Data, the user agrees to all of the Terms of Use of NYC.gov as well as the Privacy Policy for NYC.gov. The user also agrees to any additional terms of use defined by the agencies, bureaus, and offices providing data. Public data sets made available on NYC Open Data are provided for informational purposes. The City does not warranty the completeness, accuracy, content, or fitness for any particular purpose or use of any public data set made available on NYC Open Data, nor are any such warranties to be implied or inferred with respect to the public data sets furnished therein.\n",
    "\n",
    "> The City is not liable for any deficiencies in the completeness, accuracy, content, or fitness for any particular purpose or use of any public data set, or application utilizing such data set, provided by any third party.\n",
    "\n",
    "> Submitting City Agencies are the authoritative source of data available on NYC Open Data. These entities are responsible for data quality and retain version control of data sets and feeds accessed on the Site. Data may be updated, corrected, or refreshed at any time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "5EoQqNwsTqeP",
    "outputId": "18012ec1-49ca-4732-a656-2e91f8dde265",
    "tags": []
   },
   "outputs": [],
   "source": [
    "!wget https://data.rapids.ai/datasets/nyc_parking/nyc_parking_violations_2022.parquet -O /tmp/nyc_parking_violations_2022.parquet"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "hAvNFbYKWwti"
   },
   "source": [
    "# Analysis using Standard Pandas\n",
    "\n",
    "First, let's use Pandas to read in some columns of the dataset:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "SLRleX9xWxqX",
    "tags": []
   },
   "outputs": [],
   "source": [
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 554
    },
    "id": "OLatEi7rW0la",
    "outputId": "d9de97fa-8156-4547-db56-0ffd44d18faf",
    "tags": []
   },
   "outputs": [],
   "source": [
    "# read 5 columns data:\n",
    "df = pd.read_parquet(\n",
    "    \"/tmp/nyc_parking_violations_2022.parquet\",\n",
    "    columns=[\"Registration State\", \"Violation Description\", \"Vehicle Body Type\", \"Issue Date\", \"Summons Number\"]\n",
    ")\n",
    "\n",
    "# view a random sample of 10 rows:\n",
    "df.sample(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "m7qXNJU9W53D"
   },
   "source": [
    "Next, we'll try to answer a few questions using the data."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VmkFv9ZUW37g"
   },
   "source": [
    "## Which parking violation is most commonly committed by vehicles from various U.S states?\n",
    "\n",
    "Each record in our dataset contains the state of registration of the offending vehicle, and the type of parking offence. Let's say we want to get the most common type of offence for vehicles registered in different states. We can do this in Pandas using a combination of [value_counts](https://pandas.pydata.org/docs/reference/api/pandas.Series.value_counts.html) and [GroupBy.head](https://pandas.pydata.org/docs/reference/api/pandas.core.groupby.DataFrameGroupBy.head.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 423
    },
    "id": "bHXq-s_ZXOQN",
    "outputId": "df9f6c96-3348-49de-8b08-5a79186a2c4a"
   },
   "outputs": [],
   "source": [
    "(df[[\"Registration State\", \"Violation Description\"]]  # get only these two columns\n",
    " .value_counts()  # get the count of offences per state and per type of offence\n",
    " .groupby(\"Registration State\")  # group by state\n",
    " .head(1)  # get the first row in each group (the type of offence with the largest count)\n",
    " .sort_index()  # sort by state name\n",
    " .reset_index()\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8lXF4v4SXRf3"
   },
   "source": [
    "The code above uses [method chaining](https://tomaugspurger.net/posts/method-chaining/) to combine a series of operations into a single statement. You might find it useful to break the code up into multiple statements and inspect each of the intermediate results!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "H7_9EmGyXUJd"
   },
   "source": [
    "## Which vehicle body types are most frequently involved in parking violations?\n",
    "\n",
    "We can also investigate which vehicle body types most commonly appear in parking violations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 455
    },
    "id": "d7Ax-u4TXZtp",
    "outputId": "875f55f8-c568-4ecb-b134-81a955c8dd1f"
   },
   "outputs": [],
   "source": [
    "(df\n",
    " .groupby([\"Vehicle Body Type\"])\n",
    " .agg({\"Summons Number\": \"count\"})\n",
    " .rename(columns={\"Summons Number\": \"Count\"})\n",
    " .sort_values([\"Count\"], ascending=False)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VjFfQLZHXehM"
   },
   "source": [
    "## How do parking violations vary across days of the week?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "s5_y9m_AXhIw",
    "outputId": "a78faa2b-26fd-46b0-bb64-60ba43ed4f7c"
   },
   "outputs": [],
   "source": [
    "weekday_names = {\n",
    "    0: \"Monday\",\n",
    "    1: \"Tuesday\",\n",
    "    2: \"Wednesday\",\n",
    "    3: \"Thursday\",\n",
    "    4: \"Friday\",\n",
    "    5: \"Saturday\",\n",
    "    6: \"Sunday\",\n",
    "}\n",
    "\n",
    "df[\"Issue Date\"] = df[\"Issue Date\"].astype(\"datetime64[ms]\")\n",
    "df[\"issue_weekday\"] = df[\"Issue Date\"].dt.weekday.map(weekday_names)\n",
    "\n",
    "df.groupby([\"issue_weekday\"])[\"Summons Number\"].count().sort_values()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "LDeYr6xkXiDc"
   },
   "source": [
    "It looks like there are fewer violations on weekends, which makes sense! During the week, more people are driving in New York City."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "JKBQcT64XlMr"
   },
   "source": [
    "## Let's time it!\n",
    "\n",
    "Loading and processing this data took a little time. Let's measure how long these pipelines take in Pandas:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 459
    },
    "id": "mDpQhus-Xnfs",
    "outputId": "08cd4668-1d06-43b5-f00c-845e9460fc63"
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "df = pd.read_parquet(\n",
    "    \"/tmp/nyc_parking_violations_2022.parquet\",\n",
    "    columns=[\"Registration State\", \"Violation Description\", \"Vehicle Body Type\", \"Issue Date\", \"Summons Number\"]\n",
    ")\n",
    "\n",
    "(df[[\"Registration State\", \"Violation Description\"]]\n",
    " .value_counts()\n",
    " .groupby(\"Registration State\")\n",
    " .head(1)\n",
    " .sort_index()\n",
    " .reset_index()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 490
    },
    "id": "9Gw5TWH2Xqgv",
    "outputId": "1789b873-045f-464f-f10b-26859e3ed5c8"
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "(df\n",
    " .groupby([\"Vehicle Body Type\"])\n",
    " .agg({\"Summons Number\": \"count\"})\n",
    " .rename(columns={\"Summons Number\": \"Count\"})\n",
    " .sort_values([\"Count\"], ascending=False)\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "BovQgNrpXr2l",
    "outputId": "534a9602-c9b9-45b3-8da3-995066f9b692"
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "weekday_names = {\n",
    "    0: \"Monday\",\n",
    "    1: \"Tuesday\",\n",
    "    2: \"Wednesday\",\n",
    "    3: \"Thursday\",\n",
    "    4: \"Friday\",\n",
    "    5: \"Saturday\",\n",
    "    6: \"Sunday\",\n",
    "}\n",
    "\n",
    "df[\"Issue Date\"] = df[\"Issue Date\"].astype(\"datetime64[ms]\")\n",
    "df[\"issue_weekday\"] = df[\"Issue Date\"].dt.weekday.map(weekday_names)\n",
    "\n",
    "df.groupby([\"issue_weekday\"])[\"Summons Number\"].count().sort_values()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VgAWS0yXXtGj"
   },
   "source": [
    "# Using cudf.pandas\n",
    "\n",
    "Now, let's re-run the Pandas code above with the `cudf.pandas` extension loaded.\n",
    "\n",
    "Typically, you should load the `cudf.pandas` extension as the first step in your notebook, before importing any modules. Here, we explicitly restart the kernel to simulate that behavior."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "hW5rUr2tXzUW",
    "outputId": "22066842-4cd7-48de-a49d-a08a56fdc823"
   },
   "outputs": [],
   "source": [
    "get_ipython().kernel.do_shutdown(restart=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "NjvPsTlGZrW7"
   },
   "outputs": [],
   "source": [
    "%load_ext cudf.pandas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "XL_u4l5gZJte"
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "import pandas as pd\n",
    "\n",
    "df = pd.read_parquet(\n",
    "    \"/tmp/nyc_parking_violations_2022.parquet\",\n",
    "    columns=[\"Registration State\", \"Violation Description\", \"Vehicle Body Type\", \"Issue Date\", \"Summons Number\"]\n",
    ")\n",
    "\n",
    "(df[[\"Registration State\", \"Violation Description\"]]\n",
    " .value_counts()\n",
    " .groupby(\"Registration State\")\n",
    " .head(1)\n",
    " .sort_index()\n",
    " .reset_index()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "BLWa8ed6d-pD"
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "(df\n",
    " .groupby([\"Vehicle Body Type\"])\n",
    " .agg({\"Summons Number\": \"count\"})\n",
    " .rename(columns={\"Summons Number\": \"Count\"})\n",
    " .sort_values([\"Count\"], ascending=False)\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "X6ASy4mPd_-c"
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "weekday_names = {\n",
    "    0: \"Monday\",\n",
    "    1: \"Tuesday\",\n",
    "    2: \"Wednesday\",\n",
    "    3: \"Thursday\",\n",
    "    4: \"Friday\",\n",
    "    5: \"Saturday\",\n",
    "    6: \"Sunday\",\n",
    "}\n",
    "\n",
    "df[\"Issue Date\"] = df[\"Issue Date\"].astype(\"datetime64[ms]\")\n",
    "df[\"issue_weekday\"] = df[\"Issue Date\"].dt.weekday.map(weekday_names)\n",
    "\n",
    "df.groupby([\"issue_weekday\"])[\"Summons Number\"].count().sort_values()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "FMUrf6iMeBdM"
   },
   "source": [
    "Much faster! Operations that took 5-20 seconds can now potentially finish in just milliseconds without changing any code."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "00m6gUxqeGzk"
   },
   "source": [
    "# Understanding Performance\n",
    "\n",
    "`cudf.pandas` provides profiling utilities to help you better understand performance. With these tools, you can identify which parts of your code ran on the GPU and which parts ran on the CPU.\n",
    "\n",
    "They're accessible in the `cudf.pandas` namespace since the `cudf.pandas` extension was loaded above with `load_ext cudf.pandas`.\n",
    "\n",
    "#### Colab Note\n",
    "If you're running in Colab, the first time you run use the profiler it may take 10+ seconds due to Colab's debugger interacting with the built-in Python function [sys.settrace](https://docs.python.org/3/library/sys.html#sys.settrace) that we use for profiling. For demo purposes, this isn't an issue. Just run the cell again.\n",
    "\n",
    "## Profiling Functionality\n",
    "\n",
    "We can generate a per-function profile:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "fcHVUlJoJXkK"
   },
   "outputs": [],
   "source": [
    "len(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "RFm22OWbeHF2"
   },
   "outputs": [],
   "source": [
    "%%cudf.pandas.profile\n",
    "\n",
    "small_df = pd.DataFrame({'a': [\"0\", \"1\", \"2\"], 'b': [\"x\", \"y\", \"z\"]})\n",
    "small_df = pd.concat([small_df, small_df])\n",
    "\n",
    "axis = 0\n",
    "for i in range(0, 2):\n",
    "    small_df.min(axis=axis)\n",
    "    axis = i\n",
    "\n",
    "counts = small_df.groupby(\"a\").b.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 822
    },
    "id": "Syb-_vZweN2H",
    "outputId": "bd05e9aa-7e55-4a32-a813-e53e8d2ade27"
   },
   "outputs": [],
   "source": [
    "%%cudf.pandas.line_profile\n",
    "\n",
    "small_df = pd.DataFrame({'a': [\"0\", \"1\", \"2\"], 'b': [\"x\", \"y\", \"z\"]})\n",
    "small_df = pd.concat([small_df, small_df])\n",
    "\n",
    "axis = 0\n",
    "for i in range(0, 2):\n",
    "    small_df.min(axis=axis)\n",
    "    axis = 1\n",
    "\n",
    "counts = small_df.groupby(\"a\").b.count()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VCZ6BxwBpfjL"
   },
   "source": [
    "## Behind the scenes: What's going on here?\n",
    "\n",
    "When you load `cudf.pandas`, Pandas types like `Series` and `DataFrame` are replaced by proxy objects that dispatch operations to cuDF when possible. We can verify that `cudf.pandas` is active by looking at our `pd` variable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "jogk5UrgeTkS",
    "outputId": "83079e87-3988-4df6-90eb-68acd00ff038"
   },
   "outputs": [],
   "source": [
    "pd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vxh70rpDph3I"
   },
   "source": [
    "As a result, all pandas functions, methods, and created objects are proxies:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 121
    },
    "id": "RYTCGl7spgjs",
    "outputId": "c1d915a3-29c2-46ec-db62-00dad9b5a89f"
   },
   "outputs": [],
   "source": [
    "type(pd.read_csv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9-NvKu7XplmO"
   },
   "source": [
    "Operations supported by cuDF will be **very** fast:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "MFvLJo4upnUG",
    "outputId": "f40387af-0e54-43a2-95d5-d0f403791e08"
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "df.count(axis=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Np6VP-wSpomO"
   },
   "source": [
    "Operations not supported by cuDF will be slower, as they fall back to using Pandas (copying data between the CPU and GPU under the hood as needed). For example, cuDF does not currently support the `axis=` parameter to the `count` method. So this operation will run on the CPU and be noticeably slower than the previous one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "mThydJIYpuha",
    "outputId": "b803003f-adb3-4ef0-c152-0def5aa39a2f"
   },
   "outputs": [],
   "source": [
    "%%time\n",
    "df.count(axis=1) # This will use pandas, because cuDF doesn't support axis=1 for the .count() method"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "tbDVvkP2pyra"
   },
   "source": [
    "But the story doesn't end here. We often need to mix our own code with third-party libraries that other people have written. Many of these libraries accept pandas objects as inputs."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3yK3a-mIp0vr"
   },
   "source": [
    "# Using third-party libraries with cudf.pandas\n",
    "\n",
    "You can pass Pandas objects to third-party libraries when using `cudf.pandas`, just like you would when using regular Pandas.\n",
    "\n",
    "Below, we show an example of using [plotly-express](https://plotly.com/python/plotly-express/) to visualize the data we've been processing:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "H0QwPQcAp2RV"
   },
   "source": [
    "## Visualizing which states have more pickup trucks relative to other vehicles?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 542
    },
    "id": "Ecs213eEqCd9",
    "outputId": "04c33fe3-c170-4078-a96f-e8adf1ca8336"
   },
   "outputs": [],
   "source": [
    "import plotly.express as px\n",
    "\n",
    "df = df.rename(columns={\n",
    "    \"Registration State\": \"reg_state\",\n",
    "    \"Vehicle Body Type\": \"vehicle_type\",\n",
    "})\n",
    "\n",
    "# vehicle counts per state:\n",
    "counts = df.groupby(\"reg_state\").size().sort_index()\n",
    "# vehicles with type \"PICK\" (Pickup Truck)\n",
    "pickup_counts = df.where(df[\"vehicle_type\"] == \"PICK\").groupby(\"reg_state\").size()\n",
    "# percentage of pickup trucks by state:\n",
    "pickup_frac = ((pickup_counts / counts) * 100).rename(\"% Pickup Trucks\")\n",
    "del pickup_frac[\"MB\"]  # (Manitoba is a huge outlier!)\n",
    "\n",
    "# plot the results:\n",
    "pickup_frac = pickup_frac.reset_index()\n",
    "px.choropleth(pickup_frac, locations=\"reg_state\", color=\"% Pickup Trucks\", locationmode=\"USA-states\", scope=\"usa\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9bgMrWs5qDG_"
   },
   "source": [
    "## Beyond just passing data: **Accelerating** third-party code\n",
    "\n",
    "Being able to pass these proxy objects to libraries like Plotly is great, but the benefits don't end there.\n",
    "\n",
    "When you enable `cudf.pandas`, pandas operations running **inside the third-party library's functions** will also benefit from GPU acceleration where possible!\n",
    "\n",
    "Below, you can see an image illustrating how `cudf.pandas` can accelerate the pandas backend in Ibis, a library that provides a unified DataFrame API to various backends. We ran this example on a system with an NVIDIA H100 GPU and an Intel Xeon Platinum 8480CL CPU.\n",
    "\n",
    "\n",
    "By loading the `cudf.pandas` extension, pandas operations within Ibis can use the GPU with zero code change. It just works."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8JW2CQL6qEv3"
   },
   "source": [
    "![ibis](https://drive.google.com/uc?id=1uOJq2JtbgVb7tb8qw8a2gG3JRBo72t_H)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pyVNtGUhtFs5"
   },
   "source": [
    "# Conclusion\n",
    "\n",
    "With `cudf.pandas`, you can keep using pandas as your primary dataframe library. When things start to get a little slow, just load the `cudf.pandas` and run your existing code on a GPU!\n",
    "\n",
    "To learn more, we encourage you to visit [rapids.ai/cudf-pandas](https://rapids.ai/cudf-pandas)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "XjELOIf3xykH"
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "gpuType": "T4",
   "provenance": [],
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
